const common = require('./base/common');

/**
 * 1631. 最小体力消耗路径
 * 
 * Note: 
 * 1. 二分法解决该问题的核心是，如何将问题转化为一个判定性问题，如本题就是构造一个命题“是否存在一条从左上角到右下角的路径，其经过的所有边权的最大值不超过 x？”
 * 2. 二分法需要保证x是一个有限的数字，不然无法使用折半的方式去逼近
 * 3. 构建一个判定器，输入为x，输出为x是否满足要求，据此可以进行上下界限的变更
 * 
 * @kind 二分法
 * @param {*} heights 
 */
var minimumEffortPath = function(heights) {
    const dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]];

    const m = heights.length, n = heights[0].length;
    let left = 0, right = 999999, ans = 0;
    while (left <= right) {
        const mid = (left + right) >> 1;
        const queue = [[0, 0]];
        const seen = new Array(m * n).fill(0);
        seen[0] = 1;
        while (queue.length) {
            const [x, y] = queue.shift();
            for (let i = 0; i < 4; i++) {
                const nx = x + dirs[i][0];
                const ny = y + dirs[i][1];
                if (nx >= 0 && nx < m && ny >= 0 && ny < n && !seen[nx * n + ny] && Math.abs(heights[x][y] - heights[nx][ny]) <= mid) {
                    queue.push([nx, ny]);
                    seen[nx * n + ny] = 1;
                }
            }
        }
        if (seen[m * n - 1]) {
            ans = mid;
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return ans;
};

common.testing([
    [[1,2,2],[3,8,2],[5,3,5]],
    [[1,2,3],[3,8,4],[5,3,5]],
    [[1,2,1,1,1],[1,2,1,2,1],[1,2,1,2,1],[1,2,1,2,1],[1,1,1,2,1]]
], [2, 1, 0])(x => minimumEffortPath(x));